<?php
class MysqlDao extends Dao {
    public $sequence = false;
    protected $intTypeLen = array('tinyint'=>4, 'smallint'=>6, 'int'=>11, 'bigint'=>20);
    
    protected function __construct($connSetting, $connName=DEFAULT_CONN) {
        parent::__construct($connSetting);
        $charset = str_replace('-', '', strtolower($connSetting['DBCHARSET']));
        $this->setConn($connName);
        $this->execute('SET NAMES ' . $charset);
    }
    
    protected function getDsn($connSetting) {
        $port = $connSetting['DBPORT'] ? $connSetting['DBPORT'] : 3306;
        return 'mysql:host=' . $connSetting['DBHOST'] . ';dbname=' . $connSetting['DBNAME'] . ';port=' . $port;
    }
    /**
     * 从数据表获取表元数据
     * @param String $tableName
     * @return array
     */
    public function getMetadata($tableName) {
        $tableName = strtolower($this->dbPrefix . $tableName);
        $tableKeys = $this->getTableKeys($tableName);
        $uniqueKeys = $tableKeys['uniqueKeys'];
        $notnullColumns = array();
        if (is_array($uniqueKeys)) {
            foreach ($uniqueKeys as $keyName => $columns) {
                $notnullColumns = array_merge($notnullColumns, $columns);
            }
            $notnullColumns = array_unique($notnullColumns);
        }
        $strQuery = 'DESC ' . $tableName;
        $columnList = $this->getAll($strQuery);
        $columns = array();
        foreach ($columnList as $column) {
            $extra = 'PUMP_COL_TYPE_CUSTOM';
            $columnName = $column['field'];
            if(false !== stripos($column['type'], 'int')) {
                $intType = preg_replace('/\(.+/', '', $column['type']);
                $columns[$columnName]['type'] = 'Number(' . $this->intTypeLen[$intType] . ')';
            } else if (preg_match('/decimal|float|double/i', $column['type'])) {
                $columnLen = trim(strrchr($column['type'], '('), '()');
                $columns[$columnName]['type'] = 'Number(' . $columnLen . ')';
            } else if (preg_match('/char|text/', $column['type'])) {
                $columLen = trim(strrchr($column['type'], '('), '()');
                if ($columLen) {
                    $columns[$columnName]['type'] = 'String(' . $columLen . ')';
                } else {
                    $columns[$columnName]['type'] = 'String';
                }
            } else if (false !== stripos($column['type'], 'date')) {
                $columns[$columnName]['type'] = ucfirst($column['type']);
            }
            $columns[$columnName]['notnull'] = $column['null'] == 'YES' ? false : true;
            if(false == $columns[$columnName]['notnull'] && in_array($columnName, $notnullColumns)) {
                throw new Exception('数据表"' . $tableName . '"的字段"' . $columnName . '"被唯一索引使用，建议此列设置为非空字段');
            }
            $columns[$columnName]['default'] = $column['default'];
            if($column['default']) $columns[$columnName]['notnull'] = true;
            if ('PRI' == $column['key']) {
                if ('auto_increment' == $column['extra']) {
                    $extra = 'PUMP_COL_TYPE_INCREMENT';
                } elseif (false !== stripos($columns[$columnName]['default'], COL_TYPE_UUID) ||   false !== stripos($columns[$columnName]['type'],'char(36)')) {
                    $extra = 'PUMP_COL_TYPE_UUID';
                }
                $columns[$columnName]['extra'] = $extra;
            }
            if (in_array($columnName, Table::$createTimeArray)) {
                $createAt = $columnName;
            }
            if (in_array($columnName, Table::$updateTimeArray)) {
                $updateAt = $columnName;
            }
        }
        $metadata = array('columns'=>$columns,
                          'create_at'=>$createAt,
                          'update_at'=>$updateAt,
                          'primaryKey'=>$tableKeys['primary'] ? $tableKeys['primary'] : array(),
                          'uniqueKeys'=>$tableKeys['uniqueKeys'] ? $tableKeys['uniqueKeys'] : array(),
                          'indexes'   =>$tableKeys['indexes'] ? $tableKeys['indexes'] : array());

        return $metadata;
    }
    
    /**
     * 取得数据表主键，唯一索引，及索引信息
     * @param String $tableName
     * @return array
     */
    private function getTableKeys($tableName) {
        $strQuery = 'SHOW INDEX FROM ' . $tableName;
        $keyList = $this->getAll($strQuery);
        $keys = array();
        foreach ($keyList as $row) {
            if ('PRIMARY' == $row['key_name']) {
                $keys['primary'][] = $row['column_name'];
            } else {
                if (0 == $row['non_unique']) {
                    $keys['uniqueKeys'][$row['key_name']][] = $row['column_name'];
                } else {
                    $keys['indexes'][$row['key_name']][] = $row['column_name'];
                }
            }
        }
        return $keys;
    }

    /**
     * 取得数据库所有表
     * @return array
     */
    public function getAllTables() {
        if (0 == sizeof($this->tables)) {
            $tableList = $this->getAll('SHOW TABLES', PUMP_FETCH_NUM);
            foreach ($tableList as $row) {
                $this->tables[] = preg_replace('/^' . $this->dbPrefix . '/', '', strtolower($row[0]));
            }
        }
        return $this->tables;
    }
    
    /**
     * 根据表结构建表
     *
     */
    public function createTable($tblName, $metadata) {
        $uniqueKeys = $metadata['uniqueKeys'];
        $notnullColumns = array();
        if (is_array($uniqueKeys)) {
            foreach ($uniqueKeys as $keyName => $columns) {
                $notnullColumns = array_merge($notnullColumns, $columns);
            }
            $notnullColumns = array_unique($notnullColumns);
        }
        $tableName = strtolower($this->dbPrefix . $tblName);
        $createQuery = 'CREATE TABLE ' . $tableName . '(';
        $columns = array();
        foreach ($metadata['columns'] as $columnName=>$column) {
            $columnLen = strrchr($column['type'], '(');
            if (COL_TYPE_UUID == $column['extra']) {
                $columnLen = '(36)';
                $column['default'] = COL_TYPE_UUID;
            }
            if (false !== stripos($column['type'], 'String')) {
                if ('' != $columnLen) {
                    $columnType = 'VARCHAR' . $columnLen;
                } else {
                    $columnType = 'text';
                }
            } elseif (false !== stripos($column['type'], 'Number')) {
                if ($columnLen) {
                    if(strrchr($columnLen, ',')) {
                        $columnType = 'numeric' . $columnLen;
                    } else {
                        $len = abs(trim($columnLen, '()'));
                        foreach ($this->intTypeLen as $type=>$typeLen) {
                            if($len <= $typeLen) {
                                $columnType = $type . $columnLen;
                                break;
                            }
                        }
                    }
                } else {
                    $columnType = 'bigint';
                }
            } elseif (false !== stripos($column['type'], 'Date')) {
                $columnType = $column['type'];
            }
            $notnull = $column['notnull'] || in_array($columnName, $notnullColumns) ? 'NOT NULL' : '';
            $default = '';
            if ('' != $column['default']) {
                if (false !== stripos($column['type'], 'Number')) {
                    $default = 'DEFAULT ' . $column['default'];
                } else {
                    $default = "DEFAULT '" . $column['default'] . "'"; 
                }
            }
            $extra = '';
            if (COL_TYPE_INCREMENT == $column['extra']) {
                $extra = 'AUTO_INCREMENT';
            }
            $columns[] = $columnName . ' ' . $columnType . ' ' . $notnull . '  ' . $default . ' ' . $extra;
        }
        $createQuery .= implode(',', $columns);
        if (sizeof($metadata['primaryKey']) > 0) {
            $createQuery .= ',primary key (' . implode(',', $metadata['primaryKey']) . ')';
        }
        if (sizeof($metadata['uniqueKeys']) > 0) {
            foreach ($metadata['uniqueKeys'] as $uniqueKey=>$fields) {
                $createQuery .= ',UNIQUE KEY ' . $uniqueKey . '(' . implode(',', $fields) . ')';
            }
        }
        if (sizeof($metadata['indexes']) > 0) {
            foreach ($metadata['indexes'] as $uniqueKey=>$fields) {
                $createQuery .= ',KEY ' . $uniqueKey . '(' . implode(',', $fields) . ')';
            }
        }
        $createQuery .= ') ENGINE=INNODB DEFAULT CHARSET=utf8';
        
        if ($this->execute($createQuery)) {
            $this->tables[] = $tblName;
            return true;
        } else {
            throw new Exception('数据表"' . $tableName . '"创建失败，请手工创建<br />' . $createQuery);
        }
    }
    
    
    /**
     * 限制返回记录数
     */
    public function limit($strQuery, $limit) {
        return $strQuery . ' LIMIT ' . $limit;
    }
}
?>